简体   繁体   English

如何使用OOP进行设计

[英]How to design this using OOP

I have an object called User, with properties like Username, Age, Password email etc. 我有一个名为User的对象,其中包含Username,Age,Password email等属性。

I initialize this object in my ado.net code like: 我在ado.net代码中初始化此对象,如:

private User LoadUser(SqlDataReader reader)
{
      User user = new User();

      user.ID = (int)reader["userID"];
      // etc
}

Now say I create a new object that inherits from User, like: 现在说我创建一个继承自User的新对象,如:

public class UserProfile : User
{
     public string Url {get;set;}
}

Now I need to create a method that will load the userprofile, so currently I am doing: 现在我需要创建一个加载userprofile的方法,所以目前我在做:

public UserProfile LoadUserProfile(SqlDataReader reader)
{
         UserProfile profile = new UserProfile();

         profile.ID = (int)reader["userID"];
         // etc. copying the same code from LoadUser(..)
         profile.Url = (string) reader["url"];
}

Is there a more OOP approach to this so I don't have to mirror my code in LoadUserProfile() from LoadUser()? 是否有更多的OOP方法,所以我不必从LoadUser()在LoadUserProfile()镜像我的代码?

I wish I could do this: 我希望我能做到这一点:

UserProfile profile = new UserProfile();

profile = LoadUser(reader);

// and then init my profile related properties

Can something like this be done? 可以这样做吗?

Move the LodUser method to the User Base class and make it virtual. 将LodUser方法移动到User Base类并使其成为虚拟。 Then, in the UserProfile method, you override this method. 然后,在UserProfile方法中,您重写此方法。

public class User
{
   public virtual void Load(SqlDataReader reader)
   {
      this.Id = reader["Id"];
      //.. whatever else
   }
}

public class UserProfile : User
{
   public string ExtraProp {get;set;}
   public override void Load(SqlDataReader reader)
   {
      base.Load(reader);
      this.ExtraProp = reader["ExtraProp"];
   }
}

Then you can just do something like: 然后你可以做一些像:

UserProfile up = new UserProfile();
up.Load(myReader);

i dont really understand why user profile inherits from User, logically to me it doesnt make much sense. 我真的不明白为什么用户配置文件继承自用户,从逻辑上讲,它没有多大意义。

what makes sense to me is 对我来说有意义的是

public class UserProfile
{
     User user;
     public string Url {get;set;}
}

then you could have something like 然后你可以有类似的东西

public UserProfile LoadUserProfile(SqlDataReader reader)
{
         User user = LoadUser(reader);
         UserProfile profile = new UserProfile(user);

          //load profile stuff from reader...
         return profile;
}

First of all why is your userprofile inheriting from user. 首先,为什么你的userprofile继承自用户。 UserProfile is not User. UserProfile不是User。 Convinence inheritance at its worst. 最糟糕的是,他的遗传继承。

If you don't want your User and UserProfile objects to know about SQL (persistence ignorance = good), you could use static/extension methods that operate on an existing object: 如果您不希望User和UserProfile对象知道SQL(persistence ignorance = good),您可以使用对现有对象进行操作的静态/扩展方法:

private static User LoadFromReader(this User user, SqlDataReader reader)
{
      user.ID = (int)reader["userID"];
      // etc

      return user;
}

public UserProfile LoadFromReader(this UserProfile profile, SqlDataReader reader)
{
     ((User)profile).LoadFromReader(reader);

     profile.Url = (string) reader["url"];
     // etc

     return profile;
}

Then the calling code could look like this: 然后调用代码可能如下所示:

UserProfile profile = new UserProfile().LoadFromReader(reader);

I would change it to: 我会把它改成:

 class User 
 {
      public User(SqlDataReader reader)
      {
          Initialize(reader);
      }

      protected virtual void Initialize(SqlDataReader reader)
      {
           this.ID = (int)reader["userID"];
       // etc
      }
 }

 class UserProfile : User
 {
      public UserProfile(SqlDataReader reader) : base(reader) {}

      protected override void Initialize(SqlDataReader reader)
      {
           base.Initialize(reader); // Initialize "user" variables
           this.MyProperty = (int)reader["myProperty"];
      }
 }

This way, each class initializes its own values (handled from the constructor), and you only have the code in one place. 这样,每个类初始化自己的值(从构造函数处理),并且只在一个地方有代码。

I would go with a Factory class here. 我会去这里的工厂课。 It would keep things separated to address Single Responsibility Principle :. 它会将事情分开来解决单一责任原则 :。 I'm also basing my answer in that the building properties of User are all accessible from UserProfile . 我的答案也是基于User的构建属性都可以从UserProfile访问。 A constructor of UserProfile could accept a User and fetch all it's properties. UserProfile的构造函数可以接受User并获取其所有属性。

    public static class UserFactory
    {
        public static User LoadUser(SqlDataReader reader)
        {
            int id = (int)reader["userID"];
            return new User(id);
        }

        public static UserProfile LoadUserProfile(SqlDataReader reader)
        {
            User user = LoadUser(reader);
            // extra properties
            string url = (string)reader["url"];
            return new UserProfile(user, url);
        }
    }

Make LoadUser virtual and public. 使LoadUser虚拟和公共的。 In UserProfile override it. UserProfile覆盖它。

The simple answer is to override the LoadUser function and call base.LoadUser(reader) at the top of the override function definition in UserProfile class then grab the rest of the data as needed for the UserProfile class. 简单的答案是覆盖LoadUser函数并在UserProfile类的覆盖函数定义顶部调用base.LoadUser(reader),然后根据UserProfile类的需要获取其余数据。

As a general rule, this setup should not use inheritance, but aggregation. 作为一般规则,此设置不应使用继承,而应使用聚合。 However for the purpose of illustrating the point, it will do. 然而,为了说明这一点,它将会这样做。

Make a constructor that takes a reader: 制作一个带读者的构造函数:

public User(DbDataReader reader) {
   ID = reader.GetInt32(reader.GetOrdinal("userID"));
   // etc
}

Usage: 用法:

User adam = new User(reader);

Then you can just make the constructor in UserProfile call the base constructor: 然后你可以让UserProfile中的构造函数调用基础构造函数:

public UserProfile(DbDataReader reader) : base(reader) {
   Url = reader.GetString(reader.GetOrdinal("url"));
}

I would have user profile be a member of the user class 我希望用户配置文件是用户类的成员

public class User
{
//...all current members of the user class...

     UserProfile profile;
}

public class UserProfile
{

     public string Url {get;set;}

}

Other than that, I would do something along the lines of Reed Copsey's answer 除此之外,我会按照Reed Copsey的回答做一些事情

It kind-of sounds like you want to do something like the following: 它听起来像你想要做的事情如下:

public class User { public Guid Id { get; set; } }
public class UserProfile : User { public string Url { get; set; } }

class MyReader
{
    private T LoadUser<T>(IDataReader reader)
        where T : User, new()
    {
        T user = new T();
        user.Id = reader.GetGuid(reader.GetOrdinal("userID"));
        return user;
    }

    public UserProfile LoadUserProfile(IDataReader reader)
    {
        UserProfile profile = LoadUser<UserProfile>(reader);
        profile.Url = (string)reader["url"];
        return profile;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM