问题
I'm making a change to an API that serves data. Some of the searches require data about an author and take a IAuthor object. The API has an IAuthor interface and a single concrete class that implements IAuthor called Author.
I need to add a boolean property, IsNovelist that will change the semantics of some but not all searches.
I've heard about the open/closed principle and it would seem that changing the IAuthor and/or Author classes would violate this. How then to make this simple change?
UPDATE:
Perhaps I was concentrating on the wrong class. I don't want to add behaviour to Author class (it's just a way of passing parameters to the API). So a Decorated author wouldn't need a boolean flag because it would be isNovelist == true by implication.
I need to change the behaviour of the GetBooks method given an author who is flagged as being a novelist. So something more like this but my thinking is probably wonky because now I'm changing (not extending) the Books class:
//Before
class Books
{
public Books[] GetBooks(IAuthor author){
// Call data access GetBooks...
}
}
//After
class Books
{
public Books[] GetBooks(IAuthor author){
// To maintain pre-existing behaviour
// call data access GetBooks with SQL param @isNovelist = false...
// (or don't pass anything because the SQL param defaults to false)
}
public Books[] GetBooksForNovelist(IAuthor author){
// To get new behaviour
// call data access GetBooks with SQL param @isNovelist = true
}
}
回答1:
Solution 2 :
class Program
{
private static void Main(string[] args)
{
IAuthor author = new Novelist();
author.Name = "Raj";
// i guess u have check if author is a novelist
// the simple way is by safe typecasting
Novelist novelist = author as Novelist;
if (novelist != null)
{
Console.WriteLine("Wohoo, i am a novelist");
}
else
{
Console.WriteLine("Damn,i cant write novel");
}
}
Solution 1 :
public enum AuthourType
{
Novelist,
Other
}
public interface IAuthor
{
string Name { get; set; }
AuthourType Type { get; set; }
}
public class Novelist : IAuthor
{
public string Name { get; set; }
public AuthourType Type { get; set; }
// incase u dont want it to be set to other value
/*
public AuthourType Type
{
get { return type; }
set
{
if (value != AuthourType.Novelist)
{
throw new NotSupportedException("Type");
}
type = value;
}
}
*/
}
回答2:
Here is how you do using the decorator pattern
interface IAuthor
{
void someMethod();
}
class Author:IAuthor{
public void someMethod(){
//Implementation here
}
}
//Class that will add the extra behavior.
class DecoratedAuthor : IAuthor
{
IAuthor author;
public bool isNovelist{get;set;}//Add the extra Behavior
public DecoratedAuthor(IAuthor auth)
{
this.author = auth;
}
public void someMethod(){
//Call the Author's version here
author.someMethod();
//check if he is a novelist
isNovelist = true;
}
}
public class program{
public static void Main(string[] args)
{
IAuthor auth = new Author();
DecoratedAuthor novAuth = new DecoratedAuthor(auth);
DecoratedAuthor.someMethod();
//see if he is a novelist
Console.WriteLine(novAuth.isNovelist);
}
}
来源:https://stackoverflow.com/questions/14373531/how-to-extend-class